/*
 DNN Content Builder - sourceforge.net/projects/dnncb
 Copyright (c) 2004-2008
 by Emerson Lopes (emersonlopes@gmail.com)

 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
 documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
 the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
 to permit persons to whom the Software is furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all copies or substantial portions 
 of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
 TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 DEALINGS IN THE SOFTWARE.
*/

using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;

namespace DNNContentBuilder.UserControls
{
	using System;
	using System.Collections;
	using System.Web.UI;
	using System.Web.UI.HtmlControls;
	using System.Web.UI.WebControls;
	using System.Text;
	using System.Xml;
	using DotNetNuke;
	using DotNetNuke.Common.Utilities;
	using DNNContentBuilder.UserControls.FieldControls;
    using System.Web;

	/// <summary>
	/// Controls the display mode of the form engine.
	/// </summary>
	public enum FormEngineDisplayMode
	{
		None,
		Create,
		Update,
		Workflow
	}

	/// <summary>
	///		Summary description for FormEngineControl.
	/// </summary>
	public class FormEngineControl : System.Web.UI.UserControl
	{
		// TODO: replace the redundant code within this class with an instance of the FormEngine control

		#region Controls
		protected System.Web.UI.WebControls.LinkButton btUpdate;
		protected System.Web.UI.WebControls.LinkButton btDelete;
		protected System.Web.UI.WebControls.LinkButton btCancel;
		protected System.Web.UI.WebControls.LinkButton btUnPublish;
		public    System.Web.UI.WebControls.LinkButton btHistory;
		protected System.Web.UI.WebControls.LinkButton btRejectTask;
		protected System.Web.UI.WebControls.TextBox txtContentId;
		protected System.Web.UI.WebControls.PlaceHolder plcFields;
		protected System.Web.UI.WebControls.PlaceHolder plcError;
		protected System.Web.UI.WebControls.PlaceHolder plcFormEngine;
		protected DNNContentBuilder.UserControls.PublishingSecurityControl SecurityRoles;
		protected DNNContentBuilder.UI.WebControls.DummyPostBackHandler PostBackHandler;
		protected TaxonomyTreeView TaxonomyTreeView;
		#endregion

		#region Constants
		private const string primaryKeyValueKey = "PrimaryKeyValue";
		public const string resource = "~/DesktopModules/DNNContentBuilder/App_LocalResources/FormEngineControl";
		private const string eventResource = "~/DesktopModules/DNNContentBuilder/App_LocalResources/MetaDataEvent";
		private const string IGNORE_USER_ROLES = "<IGNORE_ROLES>";
		#endregion
		
		#region Member Variables
		private Hashtable formlets = new Hashtable();
		private ContentManagerSettingsInfo cmsInfo;
		private ContentManagerSettingsController cmsController = new ContentManagerSettingsController();
		private ControlTypeController ctController = new ControlTypeController();
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the display mode last set.
		/// </summary>
		[Bindable(false)]
		[Browsable(true)]
		[DefaultValue(FormEngineDisplayMode.None)]
		private FormEngineDisplayMode DisplayMode
		{
			get
			{
				object viewState = this.ViewState["DisplayMode"];

				if (viewState != null)
				{
					return (FormEngineDisplayMode)viewState;
				}

				return FormEngineDisplayMode.None;
			}
			set
			{
				this.ViewState["DisplayMode"] = value;
			}
		}

		/// <summary>
		/// Gets or sets the value of the primary key field of the 
		/// field currently under editing.
		/// </summary>
		public Guid PrimaryKeyValue
		{
			get
			{
				if (this.ViewState[primaryKeyValueKey] == null)
				{
					this.ViewState[primaryKeyValueKey] = Guid.NewGuid().ToString();
				}

				object savedState = this.ViewState[primaryKeyValueKey];

				return new Guid((string)savedState);
			}
			set
			{
				this.ViewState[primaryKeyValueKey] = value.ToString();
			}
		}
		#endregion

		#region Event Handlers
		private void Page_Load(object sender, System.EventArgs e)
		{
			this.btUpdate.Text     = Commons.GetLocalizedString("button_Update", resource);
			this.btCancel.Text     = Commons.GetLocalizedString("button_Cancel", resource);
			this.btDelete.Text     = Commons.GetLocalizedString("button_Delete", resource);
			this.btUnPublish.Text  = Commons.GetLocalizedString("button_UnPublish", resource);
			this.btHistory.Text    = Commons.GetLocalizedString("button_History", resource);
			this.btRejectTask.Text = Commons.GetLocalizedString("button_RejectTask", resource);

			if (!this.IsPostBack)
			{
				this.btDelete.Attributes.Add("onClick", "javascript:return confirm('" + Commons.GetLocalizedString("label_ConfirmDelete", resource) + "')");
				
				if (this.DisplayMode != FormEngineDisplayMode.Workflow) {
					this.btUpdate.Text = Commons.GetLocalizedString("button_Update", resource);
				}
			}

			// Set default mode to "Create Content".
			if (this.DisplayMode == FormEngineDisplayMode.None)
			{
				DisplayMode = FormEngineDisplayMode.Create;
			}

			// Restore whatever was the last display mode
			SetMode(this.DisplayMode);
			
			this.LoadFields();
		}

//		private void btHistory_Click(object sender, EventArgs e) {
//			
//		}
		
		private void btUpdate_Click(object sender, EventArgs e)
		{
			if (Page.IsValid)
			{
				// Synchronize parent and child subforms
				AddLinkerFormlets();

				// Update the database, returning content metadata

				MetaDataInfo metadata = new MetaDataInfo();
				
				try {
					metadata = UpdateDataStore();
				}
				
				catch (Exception err) {
					ErrorProvider.AddErrorMessage(plcError, err.Message, resource);
					return;
				}
				
				bool hasOpenTasks = false;
				
				MetaDataTaskInfo mtInfo = new MetaDataTaskInfo();

				ContentManagerSettingsInfo cmsInfo = cmsController.GetByModule(ContextUtil.GetModuleId(this));
					
				switch(DisplayMode)
				{
					case FormEngineDisplayMode.Create:
						if (cmsInfo.WorkflowId  != Null.NullInteger) {
							hasOpenTasks= true;
                            HttpContext.Current.Items.Add("metadataId", metadata);
						}
						
						break;
						
					case FormEngineDisplayMode.Update:
						if (DisplayMode == FormEngineDisplayMode.Update && metadata.Status != MetaDataStatus.Published) {
							hasOpenTasks = true;
							ReCreateTasks(metadata);
						}

						if (cmsInfo.WorkflowId  == Null.NullInteger) {
							hasOpenTasks= false;
						}

						break;
					
					case FormEngineDisplayMode.Workflow:
						 mtInfo = FinishCurrentTask(metadata);
						 
		 				 if (mtInfo != null) {
							//Notify next task owner, returning false if there is no tasks
							hasOpenTasks = NotifyNextTaskOwner(mtInfo);
						 }
						break;
				}
			
				if (!hasOpenTasks) {
					// Schedule content for publishing
					OpenScheduleContentDialog(metadata, mtInfo);
				} else {
					Response.Redirect(DotNetNuke.Common.Globals.NavigateURL());
				}
			}

		}
		
		private bool ReCreateTasks(MetaDataInfo metadata) {
			DbContentController dbController = new DbContentController(metadata.FormDefinitionId, ContextUtil.GetPortalId(this));

			ContentManagerSettingsInfo cmsInfo = cmsController.GetByModule(ContextUtil.GetModuleId(this));

			
			dbController.ReStartWorkflow(metadata.MetaDataId, cmsInfo);

				return true;
		}
		
		private MetaDataTaskInfo FinishCurrentTask(MetaDataInfo metaDataInfo) {
			if (this.DisplayMode == FormEngineDisplayMode.Workflow) {
				MetaDataController mdController = new MetaDataController();
				
				MetaDataInfo mdInfo = mdController.GetMetaDataByPKValue(this.PrimaryKeyValue.ToString(), IGNORE_USER_ROLES);
				
				MetaDataTaskController tk = new MetaDataTaskController();
				
				MetaDataTaskInfo mtInfo = tk.GetCurrentTask(mdInfo.MetaDataId);
				
				if (mtInfo != null) {
					mtInfo.Status  = TaskStatus.Finished;
					mtInfo.FinishDate = System.DateTime.Now;
					tk.Update(mtInfo);
				
					MetaDataEventController meController = new MetaDataEventController();
				
					MetaDataEventInfo meInfo = new MetaDataEventInfo();
					
					meInfo.Description = Commons.GetLocalizedString("label_ContentReceivedApproval", eventResource);
					meInfo.Details     = mtInfo.Title;
					meInfo.MetaDataId  = mdInfo.MetaDataId;
					meInfo.EventDate   = mtInfo.FinishDate;
					meInfo.UserId      = ContextUtil.GetUserId(this);
					meInfo.EventType   = TypeOfEvent.Approved;

					meController.Add(meInfo);
				}

				return mtInfo;
			}
			
			return null;
		}

		private bool NotifyNextTaskOwner(MetaDataTaskInfo mtInfo) {
			MetaDataController mtController = new MetaDataController();
			
			MetaDataInfo metaDataInfo = mtController.GetItem(mtInfo.MetaDataId);
			
			DbContentController dbController = new DbContentController(metaDataInfo.FormDefinitionId, ContextUtil.GetPortalId(this));
			
			MetaDataTaskController taskController = new MetaDataTaskController();
			
			MetaDataTaskInfo nextTask = taskController.GetNextTask(mtInfo.MetaDataId, mtInfo.TaskOrder);
			
			// Sending notifications to the next set of approvers
			if (nextTask != null) {
				ContentManagerSettingsInfo cmsInfo = cmsController.GetByModule(ContextUtil.GetModuleId(this));
			
				MetaDataTaskOwnerController taskOwnerController = new MetaDataTaskOwnerController();
				ArrayList owners = taskOwnerController.GetNextTaskOwners(nextTask.MetaDataTaskId);
				dbController.SendNotification(owners, nextTask.MetaDataTaskId, cmsInfo);
				return true;
			}
			
			// if reach this point, there are no approvals remaining...content is ready to publish
			return false;
		}
		
		private void btDelete_Click(object sender, EventArgs e)
		{
			// Perform a DELETE statement against the data store
			
			try 
			{
				DeleteFromDataStore();
			}

			catch (Exception ) {
					ErrorProvider.AddErrorMessage(plcError, "ERR_DELETION_CANCELED", resource);
					plcError.Visible=true;
			}
			
			Response.Redirect(DotNetNuke.Common.Globals.NavigateURL());
		}

		private void btCancel_Click(object sender, EventArgs e)
		{
			Response.Redirect(DotNetNuke.Common.Globals.NavigateURL());
		}

		private void btUnPublish_Click(object sender, EventArgs e)
		{
			UnPublishMetaDataContent(ContextUtil.GetUserId(this));
			
			Response.Redirect(DotNetNuke.Common.Globals.NavigateURL());

		}

		private void PostBackHandler_PostBack(object sender, DNNContentBuilder.UI.WebControls.PostBackEventArgs e)
		{
			// Clear the form in preparation for new content.
			Response.Redirect(DotNetNuke.Common.Globals.NavigateURL());
		}
		#endregion

		#region Methods
		/// <summary>
		/// Reset all form controls
		/// </summary>
		public void Clear()
		{
//			plcFields.Controls.Clear();
			
			this.ViewState.Remove(primaryKeyValueKey);
			this.Session.Remove(FormEngineChildControl.SessionKey);

			foreach (IFormlet formlet in this.formlets.Values)
			{
				if (formlet is LinkerControl)
				{
					((LinkerControl)formlet).Clear();
				}
			}
		}

		/// <summary>
		/// Load and render the fields contained in the form specification
		/// for the associated module.
		/// </summary>
		private void LoadFields()
		{
			int moduleId = ContextUtil.GetModuleId(this);

			if (moduleId != Null.NullInteger)
			{
				cmsInfo = cmsController.GetByModule(moduleId);

				if (cmsInfo == null)
				{
					// Notify the user that corrective action is needed
					ErrorProvider.AddErrorMessage(plcError, "ERR_FORM_NOT_REGISTERED", resource);
				
					// Hide the main controls
					plcFormEngine.Visible = false;
					
					return;
				}

				ArrayList fields = DbContentController.GetFields(cmsInfo.FormDefinitionId);

				// Refuse to render any controls if no primary key field is defined
				if (!IsPrimaryKeyDefined(fields))
				{
					return;
				}

				if (fields.Count > 0)
				{
					FormDefinitionController fdController = new FormDefinitionController();
					FormDefinitionInfo fdInfo = fdController.GetItem(cmsInfo.FormDefinitionId);
					
					string style = String.Format("<style>{0}</style>", fdInfo.CSS);
					
					plcFields.Controls.Add(new LiteralControl(style));	
				}

				foreach (FieldDefinitionInfo fdInfo in fields)
				{
					if (this.CanRender(fdInfo))
					{
						this.RenderControl(fdInfo);
					}
				}
			}
		}

		/// <summary>
		/// Determines if a <see cref="FieldDefinitionInfo"/> can or cannot
		/// be rendered in the current context.
		/// </summary>
		/// <param name="fdInfo"></param>
		/// <returns></returns>
		private bool CanRender(FieldDefinitionInfo fdInfo)
		{
			string tableName = fdInfo.SourceField;

			if (fdInfo.IsLinker)
			{
				XmlDocument xd = new XmlDocument();
				xd.LoadXml(fdInfo.XML);

				XmlNode node = xd.SelectSingleNode("//LinkedField");

				tableName = node.InnerText;
			}

			return fdInfo.Visible && !fdInfo.IsPrimaryKey && 
				(tableName.IndexOf(GetDrivingTable(cmsInfo.FormDefinitionId) + ".") != -1);
		}

		private void OpenScheduleContentDialog(MetaDataInfo metaData, MetaDataTaskInfo mtInfo)
		{
			string scriptKey = this.GetType().FullName + "ScheduleScript";
	
			StringBuilder arguments = new StringBuilder();
            ClientScriptManager cs = Page.ClientScript;
			Guid guid  = Guid.NewGuid();
			
			string key = String.Format("prt{0}", guid.ToString());

			arguments.AppendFormat("metadataId={0}&", metaData.MetaDataId);
			arguments.AppendFormat("ps={0}", key).Append("&");
            arguments.AppendFormat("pb={0}", cs.GetPostBackEventReference(PostBackHandler, PostBackHandler.ClientID.ToString())).Append("&");
			arguments.AppendFormat("uid={0}", ContextUtil.GetUserId(this)).Append("&");
	
			Session[guid.ToString()] = metaData.MetaDataId;

			arguments.AppendFormat("tid={0}", mtInfo.Title != null ? mtInfo.MetaDataTaskId.ToString() : "");
			
			Guid publishingSession = Guid.NewGuid();

			// passing publishing parameters via DNN cache
			DataCache.SetCache(publishingSession.ToString(), arguments);

			string path = String.Format("{0}?{1}", 
                           Page.ResolveUrl("~/DesktopModules/DNNContentBuilder/UserControls/ScheduleContent.aspx"),"settings=" + publishingSession.ToString());

			// TODO: inject the dialog modal script in the HEAD section of the page
			string script = System.IO.File.OpenText(Server.MapPath(Page.ResolveUrl("~/DesktopModules/DNNContentBuilder/js/dialogs.js"))).ReadToEnd();
			string ximage = Page.ResolveUrl("~/DesktopModules/DNNContentBuilder/images/128x128.gif");

			string scheduleScript = String.Format(@"
				<script language=""javascript"">
					{0}

					function cbDisableForm() {2}
						disableform.style.width  = window.screen.availWidth - 20;
						disableform.style.height = window.screen.availHeight;
					{3}

					cbDisableForm();
					window.onresize = cbDisableForm;

					blockEvents();
					openDGDialog(""{1}"", 320, 295);
				</script>", script, path, "{", "}");

			// Take portal settings to the cache
			Context.Cache[key] = ContextUtil.GetPortalSettings(this);

            if (!cs.IsStartupScriptRegistered(scriptKey))
			{
				cs.RegisterStartupScript(Page.GetType(), scriptKey, scheduleScript);
			}
			
			// Set last task status to Working, so if user cancel publishing, task remains open
			
			if (mtInfo != null) {
				mtInfo.Status = TaskStatus.Working;
				mtInfo.FinishDate = Null.NullDate;
				
				MetaDataTaskController mtController = new MetaDataTaskController();
				
				mtController.Update(mtInfo);
			}
		}

		/// <summary>
		/// Renders a user control that implements the <see cref="IFormlet"/>
		/// interface in a user specified manner.
		/// </summary>
		/// <param name="fdInfo"></param>
		private void RenderControl(FieldDefinitionInfo fdInfo)
		{
			ControlTypeInfo ctInfo = ctController.GetItem(fdInfo.ControlTypeId);
					
			string controlPath  = Page.ResolveUrl("~/" + ctInfo.ControlPath).ToUpper().Replace("DEF.", "CONTROL.");
			UserControl formlet = (UserControl)Page.LoadControl(controlPath);

			if (fdInfo.Tooltip != null && fdInfo.Tooltip.Length > 0)
			{
				foreach (Control c in formlet.Controls)
				{
					// TODO: handle composite controls (i.e., check for c.HasControls())
					if (c is WebControl)  ((WebControl)c).ToolTip = fdInfo.Tooltip;
					if (c is HtmlControl) ((HtmlControl)c).Attributes["title"] = fdInfo.Tooltip;
				}
			}

			if (!(formlet is IFormlet))
			{
				throw new ApplicationException("ERR_INVALID_FORMLET");
			}

			if (formlet is LinkerControl)
			{
				// TODO: remove LinkerControl coupling
				((LinkerControl)formlet).FieldDefinition = fdInfo;
			}

			plcFields.Controls.Add(new LiteralControl("<tr><td>"));
			plcFields.Controls.Add(new LiteralControl(fdInfo.Title));
			plcFields.Controls.Add(new LiteralControl("</td>"));

			plcFields.Controls.Add(new LiteralControl("<td>"));
			plcFields.Controls.Add(formlet);
			plcFields.Controls.Add(new LiteralControl("</td></tr>"));

			string xml = Commons.InsertChildNode("<CssClass>" + fdInfo.CssClass + "</CssClass>", fdInfo.XML);

			((IFormlet)formlet).SetConfig(xml);
			
			this.formlets[fdInfo.SourceField] = formlet;
		}

		/// <summary>
		/// Display the contents of a specified metadata row.
		/// </summary>
		/// <param name="info"></param>
		public void DisplayContents(MetaDataInfo info)
		{
			DisplayContents(info, null);
			
			btUnPublish.Visible = (info.Status == MetaDataStatus.Published);
		}

		public void DisplayContents(MetaDataInfo info, MetaDataTaskInfo taskInfo)
		{
			// TODO: refactor to account for child tables
			SetMode(this.DisplayMode);

			if (cmsInfo == null)
			{
				cmsInfo = cmsController.GetByModule(ContextUtil.GetModuleId(this));
			}

			string drivingTable = GetDrivingTable(cmsInfo.FormDefinitionId);

			DbContentController dcController = new DbContentController(cmsInfo.FormDefinitionId, ContextUtil.GetPortalId(this), formlets);

			ArrayList fields = dcController.GetFields(drivingTable);
			DataSet userData = dcController.Select(info);
			
			Render(fields, userData.Tables[0].Rows[0]);
			
			// Set Taxonomy
			
			TaxonomyTreeView.SelectedNode = info.TaxonomyId;
			
			TaxonomyTreeView.BuildTree();

			
			// Display selected roles
			
			ContentSecurityController csController = new ContentSecurityController();
			
			ArrayList roles = csController.GetByMetaData(info.MetaDataId);

			SecurityRoles.SetValues(roles);

			if (this.DisplayMode == FormEngineDisplayMode.Workflow) {
				btUpdate.Text  = taskInfo.Title;
			}
		}

		public void Render(ArrayList fields, DataRow row)
		{
			// TODO: refactor this. Too ugly.
			bool pkFound = false;

			// Display values for the driving table controls
			foreach (FieldDefinitionInfo fdInfo in fields)
			{
				if (!pkFound && fdInfo.IsPrimaryKey)
				{
					this.PrimaryKeyValue = new Guid(row[fdInfo.SourceField].ToString());

					// TODO: refactor this. Too ugly.
					pkFound = true;
				}

				if (CanRender(fdInfo))
				{
					DisplayControlContents(fdInfo, row);
				}
			}
			
			// Set up the linker controls
			foreach (IFormlet formlet in this.formlets.Values)
			{
				if (formlet is LinkerControl)
				{
					((LinkerControl)formlet).DataBind(this.PrimaryKeyValue);
				}
			}
		}

		/// <summary>
		/// Display the contents of a specified field.
		/// </summary>
		/// <param name="fdInfo"></param>
		private void DisplayControlContents(FieldDefinitionInfo fdInfo, DataRow dr)
		{
			IFormlet formlet = (IFormlet)this.formlets[fdInfo.SourceField];
		
			string xml = formlet.GetValue(ContextUtil.GetTypeXml());

			XmlDocument xd = new XmlDocument();

			xd.LoadXml(xml);
			
			try 
			{
				xd.SelectSingleNode("//Value").InnerXml = Commons.EncodeAngleBrackets(dr[fdInfo.SourceField].ToString());
			}
			catch (Exception ) {
				xd.SelectSingleNode("//Value").InnerXml = System.Web.HttpUtility.HtmlEncode(dr[fdInfo.SourceField].ToString());
			}
			
			try {
				xd.SelectSingleNode("//IsRequired").InnerXml = fdInfo.Required.ToString();
			}
			catch (Exception) {
				xd.SelectSingleNode("//IsRequired").InnerXml = "False";
			}
			
			formlet.SetValue(xd.InnerXml);
		}

		/// <summary>
		/// Determines whether a primary key field is defined in a list of 
		/// <see cref="FieldDefinitionInfo"/> objects.
		/// </summary>
		/// <param name="fields"></param>
		/// <returns></returns>
		private bool IsPrimaryKeyDefined(ArrayList fields)
		{
			foreach (FieldDefinitionInfo fdInfo in fields)
			{
				if (fdInfo.IsPrimaryKey)
					return true;
			}

			return false;
		}

		private void AddLinkerFormlets()
		{
			ArrayList fields = DbContentController.GetFields(cmsInfo.FormDefinitionId);

			foreach (FieldDefinitionInfo fdInfo in fields)
			{
				if (fdInfo.IsLinker && fdInfo.Visible)
				{
					LinkerControl linker = this.formlets[fdInfo.SourceField] as LinkerControl;

					if (linker.DataSource == null)
					{
						// No rows in the linker, possibly reset
						continue;
					}

					Hashtable linkerFormlets = LinkerControl.Adapter.GetFormlets(linker.DataSource);

					foreach (DictionaryEntry entry in linkerFormlets)
					{
						this.formlets[entry.Key] = entry.Value;
					}
				}
			}
		}

		/// <summary>
		/// Update the tables previously configured by the user.
		/// </summary>
		private MetaDataInfo UpdateDataStore()
		{
			//Defining resulting metadata
			MetaDataInfo drivingTableMetaData = new MetaDataInfo();
			
			int moduleId = ContextUtil.GetModuleId(this);

			if (moduleId == Null.NullInteger)
			{
				return null;
			}

			if (cmsInfo == null)
			{
				cmsInfo = cmsController.GetByModule(moduleId);
			}

			FormDataConnectionsController fdcController = new FormDataConnectionsController();

			ArrayList connections = fdcController.GetByFormDefinition(cmsInfo.FormDefinitionId);

			foreach (FormDataConnectionsInfo fdcInfo in connections)
			{
				DataConnectionInfo connectionInfo = new DataConnectionController().GetItem(fdcInfo.DataConnectionId);
				ConnectionStringController csController = new ConnectionStringController();
				
				ConnectionStringInfo csInfo = csController.GetItem(connectionInfo.ConnectionStringId);

				// Metadata added for the driving table only
				if (connectionInfo.TableName == GetDrivingTable(cmsInfo.FormDefinitionId))
				{
					DbContentController contentController = new DbContentController(fdcInfo.FormDefinitionId, ContextUtil.GetPortalId(this), this.formlets);

					// Adds support for the Linker control
					contentController.ForeignKeyValue = this.PrimaryKeyValue;

					MetaDataController mdController = new MetaDataController();
				
					if (mdController.GetMetaDataByPKValue(PrimaryKeyValue.ToString(), IGNORE_USER_ROLES) !=  null) {
						drivingTableMetaData = new MetaDataController().GetMetaDataByPKValue(PrimaryKeyValue.ToString(), IGNORE_USER_ROLES);
					} else {
						drivingTableMetaData.PKValue=PrimaryKeyValue.ToString();
					}

					//Metadata settings
					if (drivingTableMetaData.CreationDate == Null.NullDate) {
						drivingTableMetaData.CreationDate = DateTime.Now;
					}
					
					drivingTableMetaData.Status  = MetaDataStatus.Working;

					//TODO: Dollar sign must be removed in the next revision since it is an unacceptable dependency
					
					string radio = this.TaxonomyTreeView.UniqueID + "$";

					if (Page.Request.Form.Get(radio) != null) 
					{
						drivingTableMetaData.TaxonomyId = Int32.Parse(Page.Request.Form.Get(radio));
					} 
					else 
					{
						drivingTableMetaData.TaxonomyId = Null.NullInteger;
					}

					//TODO: to review that code in order to add support to versioning
					drivingTableMetaData.PublishDate 		= Null.NullDate;
					drivingTableMetaData.ExpireDate			= Null.NullDate;
					drivingTableMetaData.Title   			= contentController.GetTitleFieldValue(connectionInfo.TableName);
					drivingTableMetaData.FormDefinitionId 	= fdcInfo.FormDefinitionId;
					drivingTableMetaData.ScheduleDate	  	= Null.NullDate;
					drivingTableMetaData.DataConnectionID 	= fdcInfo.DataConnectionId;
					drivingTableMetaData.UserID			  	= ContextUtil.GetUserId(this);
					drivingTableMetaData.PortalID		  	= ContextUtil.GetPortalId(this);

					int metaDataId = contentController.Update(drivingTableMetaData, csInfo, connectionInfo, cmsInfo, SecurityRoles.SelectedRoles(), ContextUtil.GetUserId(this));
				}
				else
				{
					FieldDefinitionInfo linkerDefinition = GetLinkerDefinition(fdcInfo.FormDefinitionId, connectionInfo.TableName);

					// Validate state of the linker definition
					ArgumentValidator.CheckForNullReference(linkerDefinition, "linkerDefinition");

					LinkerControl linker = (LinkerControl)formlets[linkerDefinition.SourceField];

					// Validate state of the linker control per se
					ArgumentValidator.CheckForNullReference(linker, "linker");
					ArgumentValidator.CheckForNullReference(linker.DataSource, "linker.DataSource");
					
					LinkerController controller = new LinkerController(linkerDefinition, linker.DataSource, csInfo, connectionInfo, this.PrimaryKeyValue.ToString()); 
					controller.Update();

					// Clear the linker after we are done with it
					linker.Clear();
				}
			}

			return drivingTableMetaData;
		}

		private FieldDefinitionInfo GetLinkerDefinition(int formDefinitionId, string tableName)
		{
			ArrayList fields = new DbContentController(formDefinitionId).GetFields(tableName);

			foreach (FieldDefinitionInfo fdInfo in fields)
			{
				if (fdInfo.IsLinker)
				{
					return fdInfo;
				}
			}

			return null;
		}

		/// <summary>
		/// Performs a SQL DELETE operation against the configured 
		/// data store.
		/// </summary>
		private void DeleteFromDataStore()
		{
			int moduleId = ContextUtil.GetModuleId(this);

			if (moduleId == Null.NullInteger)
			{
				return;
			}

			if (cmsInfo == null)
			{
				cmsInfo = cmsController.GetByModule(moduleId);
			}

			FormDataConnectionsController fdcController = new FormDataConnectionsController();
			
			ArrayList connections = fdcController.GetByFormDefinition(cmsInfo.FormDefinitionId);

			foreach (FormDataConnectionsInfo fdcInfo in connections)
			{
				DbContentController 		contentController 	= new DbContentController(fdcInfo.FormDefinitionId, ContextUtil.GetPortalId(this), this.formlets);

				DataConnectionInfo 			connectionInfo 		= new DataConnectionController().GetItem(fdcInfo.DataConnectionId);
				
				ConnectionStringController 	csController 		= new ConnectionStringController();
				
				ConnectionStringInfo 		csInfo 				= csController.GetItem(connectionInfo.ConnectionStringId);

				contentController.Delete(this.PrimaryKeyValue, csInfo);
			}
		}

		private void UnPublishMetaDataContent(int userId)
		{
			DbContentController.UnPublish(this.PrimaryKeyValue, userId);
		}

		/// <summary>
		/// Scans all FieldDefinitions for the specified FormDefinition. The first table
		/// that does not contain a LinkerControl is the driving table.
		/// </summary>
		/// <returns></returns>
		/// <remarks>This method works on the assumption that there are no unrelated tables 
		/// in the form definition schema. If that assumption is not met, unpredictable side
		/// effects may result.</remarks>
		public static string GetDrivingTable(int formDefinitionId)
		{
			ArrayList fields = DbContentController.GetFields(formDefinitionId);
			StringCollection tables = GetTables(fields);
			
			ArrayList result = new ArrayList(tables);

			foreach (FieldDefinitionInfo fdInfo in fields)
			{
				if (fdInfo.IsLinker)
				{
					result.Remove(fdInfo.TableName);
				}
			}

			if (result.Count > 0)
			{
				return (string)result[0];
			}

			return String.Empty;
		}

		/// <summary>
		/// Builds a list of all table names associated with a list of 
		/// <see cref="FieldDefinitionInfo"/> entities.
		/// </summary>
		/// <param name="fields"></param>
		/// <returns></returns>
		private static StringCollection GetTables(ArrayList fields)
		{
			StringCollection result = new StringCollection();

			foreach (FieldDefinitionInfo fdInfo in fields)
			{
				if (!result.Contains(fdInfo.TableName))
				{
					result.Add(fdInfo.TableName);
				}
			}

			return result;
		}

		/// <summary>
		/// Hides or displays all command buttons.
		/// </summary>
		/// <param name="visible"></param>
		private void DisplayButtons(bool visible)
		{
			btUpdate.Visible = visible;
			btDelete.Visible = visible;
			btCancel.Visible = visible;
			btCancel.Visible = visible;
			btRejectTask.Visible = visible;
		}

		/// <summary>
		/// Selectively hides command buttons according to the specified mode.
		/// </summary>
		public void SetMode(FormEngineDisplayMode displayMode)
		{
			DisplayButtons(false);
			
			this.DisplayMode = displayMode;
			
			RenderInterface();
		}

		/// <summary>
		/// Selectively hides command buttons according with the value of the 
		/// <see cref="DisplayMode"/> property.
		/// </summary>
		private void RenderInterface()
		{
			switch (this.DisplayMode)
			{
				case FormEngineDisplayMode.Create:
					btUpdate.Visible = true;
					btCancel.Visible = true;
					btHistory.Visible = false;
					break;

				case FormEngineDisplayMode.Update:
					btUpdate.Visible = true;
					btDelete.Visible = true;
					btCancel.Visible = true;
					btHistory.Visible = true;
					break;

				case FormEngineDisplayMode.Workflow:
					btUpdate.Visible = true;
					btDelete.Visible = true;
					btCancel.Visible = true;
					btRejectTask.Visible = true;
					btHistory.Visible = true;
					break;

				default:
					throw new NotSupportedException(String.Format("Unsupported display mode: {0}", DisplayMode));
			}
		}
		#endregion

		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);
		}
		
		/// <summary>
		///		Required method for Designer support - do not modify
		///		the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.Load += new System.EventHandler(this.Page_Load);
			this.btUpdate.Click += new System.EventHandler(this.btUpdate_Click);
			this.btDelete.Click += new System.EventHandler(this.btDelete_Click);
			this.btCancel.Click += new System.EventHandler(this.btCancel_Click);
//			this.btHistory.Click += new System.EventHandler(this.btHistory_Click);
			this.btUnPublish.Click += new System.EventHandler(this.btUnPublish_Click);
			this.PostBackHandler.PostBack += new DNNContentBuilder.UI.WebControls.PostBackEventHandler(PostBackHandler_PostBack);

		}
		#endregion
	}
}
